/*
 * Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openFuyao is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

// Package v1beta1
package v1beta1

import (
	"net/http"

	"github.com/emicklei/go-restful/v3"

	"application-management-service/pkg/constant"
	"application-management-service/pkg/helm"
	helmModel "application-management-service/pkg/models/helm"
	"application-management-service/pkg/server/client"
	"application-management-service/pkg/server/filters"
	"application-management-service/pkg/server/param"
	"application-management-service/pkg/utils/httputil"
	"application-management-service/pkg/zlog"
)

var (
	multiClusterServicePluginAdmittedRole = []string{"platform-admin"}
)

// Handler Component handler
type Handler struct {
	helmOperation helm.Operation
}

func newHandler(operation helm.Operation) *Handler {
	return &Handler{helmOperation: operation}
}

func (h *Handler) getRelease(request *restful.Request, response *restful.Response) {
	// Parse parameters from the request to be used as arguments for the GetReleases function
	result, status := h.helmOperation.GetReleases(param.ReleaseParameter{
		Release:   request.QueryParameter(param.Release),
		Namespace: request.QueryParameter(param.Namespace),
		Extension: request.QueryParameter(param.Extension),
		SortBy:    request.QueryParameter(param.SortBy),
		Ascending: request.QueryParameter(param.Ascending),
		Status:    request.QueryParameters(param.Status),
	})
	_ = response.WriteHeaderAndEntity(status, result)
}

func (h *Handler) getReleaseInfo(request *restful.Request, response *restful.Response) {
	h.processGetOrDeleteAction(request, response, h.helmOperation.GetReleaseInfo)
}

func (h *Handler) deleteRelease(request *restful.Request, response *restful.Response) {
	namespace := request.PathParameter(param.Namespace)
	name := request.PathParameter(param.Release)

	// if chart is mcs, check user permission
	releaseInfo, _ := h.helmOperation.GetReleaseInfo(namespace, name)
	if helm.IsMultiClusterServiceChart(releaseInfo.Data) {
		if !filters.AuthorizeByAdmittedRoles(request, multiClusterServicePluginAdmittedRole, client.GetKubeClient()) {
			httputil.HandleNotAuthorized(response, "current user is unauthorized to delete this release", nil)
			return
		}
	}

	result, status := h.helmOperation.Uninstall(namespace, name)
	_ = response.WriteHeaderAndEntity(status, result)
}

func (h *Handler) createRelease(request *restful.Request, response *restful.Response) {
	h.processCreateOrUpgradeAction(request, response, h.helmOperation.Install)
}

func (h *Handler) upgradeRelease(request *restful.Request, response *restful.Response) {
	h.processCreateOrUpgradeAction(request, response, h.helmOperation.Upgrade)
}

func (h *Handler) getReleaseHistory(request *restful.Request, response *restful.Response) {
	namespace := request.PathParameter(param.Namespace)
	name := request.PathParameter(param.Release)

	history, status := h.helmOperation.GetReleaseHistory(namespace, name,
		helm.ParseQueryInt(request.QueryParameter("maxHistory")))
	_ = response.WriteHeaderAndEntity(status, history)
	return
}

func (h *Handler) rollbackRelease(request *restful.Request, response *restful.Response) {
	namespace := request.PathParameter(param.Namespace)
	name := request.PathParameter(param.Release)

	// if chart is mcs, check user permission
	releaseInfo, _ := h.helmOperation.GetReleaseInfo(namespace, name)
	if helm.IsMultiClusterServiceChart(releaseInfo.Data) {
		if !filters.AuthorizeByAdmittedRoles(request, multiClusterServicePluginAdmittedRole, client.GetKubeClient()) {
			httputil.HandleNotAuthorized(response,
				"current user is unauthorized to rollback this release", nil)
			return
		}
	}

	// Parse parameters from the request to be used as arguments for rolling back
	chartName := helm.GetChartName(releaseInfo.Data)
	result, status := h.helmOperation.RollbackRelease(namespace, name, chartName,
		helm.ParseQueryInt(request.QueryParameter("version")),
		helm.ParseQueryInt(request.QueryParameter("maxHistory")))
	_ = response.WriteHeaderAndEntity(status, result)
}

func (h *Handler) getHelmManifest(request *restful.Request, response *restful.Response) {
	// helper function for getting manifest/values
	h.processGetOrDeleteAction(request, response, h.helmOperation.GetManifest)
}

func (h *Handler) getHelmValues(request *restful.Request, response *restful.Response) {
	// helper function for getting values/manifest
	h.processGetOrDeleteAction(request, response, h.helmOperation.GetValues)
}

func (h *Handler) getReleasePods(request *restful.Request, response *restful.Response) {
	podsInfo, status := h.helmOperation.GetReleasePods(
		request.PathParameter(param.Namespace),
		request.PathParameter(param.Release))

	_ = response.WriteHeaderAndEntity(status, podsInfo)
}

func (h *Handler) processCreateOrUpgradeAction(request *restful.Request, response *restful.Response,
	action func(deployParams helmModel.DeployParam) (*httputil.ResponseJson, int)) {
	var deployParams helmModel.DeployParam
	if err := request.ReadEntity(&deployParams); err != nil {
		zlog.Errorf("%v", err)
		_ = response.WriteHeaderAndEntity(http.StatusBadRequest, "parse request parameter error")
		return
	}
	deployParams.Release = request.PathParameter(param.Release)
	deployParams.Namespace = request.PathParameter(param.Namespace)

	// if chart is mcs, check user permission
	if deployParams.ChartName == constant.McsChartName {
		if !filters.AuthorizeByAdmittedRoles(request, multiClusterServicePluginAdmittedRole, client.GetKubeClient()) {
			httputil.HandleNotAuthorized(response, "current user is unauthorized to create or upgrade this release",
				nil)
			return
		}
	}

	responseJson, status := action(deployParams)
	_ = response.WriteHeaderAndEntity(status, responseJson)
}

// processGetOrDeleteAction processes common tasks for Helm-related action, e.g. get_manifest, get_values --all .
func (h *Handler) processGetOrDeleteAction(request *restful.Request, response *restful.Response,
	action func(namespace, name string) (*httputil.ResponseJson, int)) {
	namespace := request.PathParameter(param.Namespace)
	name := request.PathParameter(param.Release)

	result, status := action(namespace, name)
	_ = response.WriteHeaderAndEntity(status, result)
}

func (h *Handler) checkReleaseStatus(request *restful.Request, response *restful.Response) {
	result, status := h.helmOperation.CheckReleaseStatus(request.PathParameter(param.Chart))
	_ = response.WriteHeaderAndEntity(status, result)
}
